Hey there.
The next thing that we can go ahead and script in our game is going to be the money service here on
the server.
This service is going to be responsible for randomly placing valuable items around the map that players
can collect to earn money.
So inside of server storage, we have this folder called money items that hold different types of items
that the players can collect, as well as the different positions on the map that the money items can
spawn in.
So let me go ahead and drag this folder into the workspace so we can actually see all of these.
And here are all of the different money items that players can collect.
They can collect a stack of gold bars, a singular gold bar, a singular silver bar, a stack of silver
bars.
We have a pile of coins, a singular coin, a pile of dollars, and a singular dollar.
Inside of here as well.
We have a whole bunch of positions around the map where these items can spawn in.
So as you can see, one can spawn right here.
One can spawn over here, over here, one on top of here.
And there's also a few other hidden positions around the map where these different money items can spawn
in, such as up here or over here.
And then I have one up here and things kind of like that.
And as well, if we go into the basement, there's a whole bunch of other positions spread throughout
here where our different money items can spawn at.
These different positions also have attributes on them that tell us which spawn value of money item
can spawn here.
So for example, at this position here, hidden back here, a spawn value of high or basically any of
the items here, like the gold pile or the gold bar can spawn there.
So we basically will have three different ranks of money items, ones that are low value, ones that
are medium value and then ones that are high value.
So these ones right here would be considered like high value.
I guess these ones here would be considered medium value.
And then we could have low value items over here.
So each of these different parts we set a different spawn value on them.
And then any areas where we want a money item, regardless of the value to spawn there we marked as
any.
So the plan is, is that our money service is going to basically loop through all of these different
money positions, and it's going to randomly copy one of these money items and place them at this position.
Now, since our money items have many different shapes and sizes, we're going to have to figure out
how to position these parts at these positions here while keeping them flush with the surface.
Because if we were to move this model here to this position, well, the model will be clipping through
this chest right here.
And some of the items may not be perfectly flush with the surface to make it look like they're actually
sitting on the surface.
So we're going to have to use a little bit of math to position them correctly on these different positions.
So we can go ahead and take this folder and put it back into server storage.
And we can go ahead and get started with our money service.
So we're going to need three services in here.
One is going to be server storage.
One is going to be replicated.
Storage.
And then we're going to need the server script service.
And then from this point we can create the table that will represent the service.
So money service is equal to a table.
And then at the end we can return money service.
Now some other variables that we're going to need in here are to reference a few events.
One of these events is going to be a game communication.
But this game communication is going to be a bindable event.
So we can call this game comms enum server, because this is going to be a bindable event for different
service scripts to communicate between each other.
So inside of server storage there's a folder called events.
And in there we can get the Bindesboll's dot game comms.
And that means we're going to have to create a different enum to represent the possible actions that
can be done between server scripts.
So this is not a remote event where we're giving actions to clients or clients or giving actions to
the server, but instead this is communication between different server scripts.
So inside of our server script service we have a folder in here called modules.
And in here there is a module for game communication between server scripts.
And now we can basically just go and copy one of the enums from let's say replicated storage.
So that way we don't have to type it all out by hand.
We'll just copy this and then paste it in here.
And what we could do is we could, uh, section out our game communication enum into basically actions
that can be given to different services.
So in this case, the actions we want to define are going to be for our money service.
So we can have a key called money service.
And in here we'll have a table containing all the possible actions that we can give to the money service.
And in this case this is going to be for initializing or basically placing money items around the map.
So we can call this action place money items.
And we should be good to go here.
That means we can go back in our, uh, money service and require this game comms enum so we can call
it Game Comms enum server.
And we'll require from server script service, dot server, dot modules, dot enums dot game communication
enum.
We also want to reference our update guy event and replicated storage.
That way when a player collects money, we can tell them to display that you know, money collection
frame on their screen.
And that also means we're going to have to get our Guy actions enum.
Which is then replicated.
Storage dot modules dot enums dot gui actions enum.
We're also going to be requiring another module script that is inside of the server.
And this module script is called anti-cheat.
And basically what we're going to do in here is we're just going to have one function that module scripts
on the server can require that will allow us to determine the distance that a player is away from.
Like maybe let's say a proximity prompt or a click detector or whatever.
This is, to verify that the player is actually within range of a certain click detector or a proximity
prompt to make sure that they aren't exploiting and activating click detectors or prompts from all the
way across the map.
So we can go ahead and call this anti-cheat and we'll require it from server script service.
Oops.
Let me rename that with the T as well.
Don't want to forget our T.
Dot server, dot modules, dot anti-cheat.
And then inside of our anti-cheat module script, all we'll have is a variable to represent our anti-cheat.
Make sure to return it at the end of our module script.
And then the only function that we're going to have inside of our anti-cheat is to check a player's
distance to a particular object or part in the workspace, so we can have this function be passed a
player.
An object that we want to compare the distance to.
And then we actually need the value to compare this so we can call it max distance.
And basically what we'll do is we'll get the character of this player.
If they don't have a character, then we're just going to return false.
Otherwise, we can get the distance between the player's character and this object.
By getting the position of the object and subtracting it by the character.
Dot.
Humanoid route.
Part dot position.
So this will give us a vector three that represents the distance between these two objects.
And then we can just get the magnitude of it, which will give us a number that represents how far away
this object is from our humanoid root part in studs.
Now, if this distance, uh, is less than or equal to our max distance or the threshold number that
we determined here, then we're going to return false to say, nope, they're not cheating.
Otherwise, if somehow their distance is greater than our max distance, then there's something weird
going on so we can return true.
And we can say something like unusual client behavior detected.
Now back in our money service.
The next thing that we can define here is a table that basically segregates our money items into three
different categories low value, medium value, and high value.
So we can call this money items equal to a table.
And then we can have three different categories.
So one is going to be high value.
We'll have medium value and then we'll have low value.
Now, of course, we want there to be a limit for how many different high value, medium value and low
value items we can place on the map.
So inside of each of these tables, we can create a boolean to represent whether or not we are out of
stock for a high, medium or low value item.
So we can create a key that just says out of stock and we'll set it to false as default.
And I'll just copy this and do this for the rest of the tables.
So out of stock.
And then out of stock.
And then we can go ahead and also put in here the different high value items that exist.
And we want to make sure that the names or the keys of these different items actually match the same
names as our money items.
So we'll take a look at each different money item here.
And we've already determined their value already here in an attribute.
So for example, our gold bar has a high spawn value.
And we've also set an attribute for how much money should be given to a player.
A gold pile is also worth a lot.
Um, and then, for example, our silver pile is medium value and things like that.
So one of the high value items, of course, is our gold pile.
And we'll make another table in here.
And in here we'll store the model for the gold pile which is in server storage.
Dot money items dot gold pile.
We will create a key to represent how many were allowed to place on the map.
So we can call this max allowed.
And the maximum allowed of gold piles that I want on the map are going to be two.
And then we need to keep track of how many of these gold piles are actually on the map.
So we can have another key called currently on map.
And right now that's going to be zero because we haven't spawned any in.
And then basically we can copy this and do the exact same thing for the gold bar and then make a reference
to our gold bar, the Max allowed on the map.
We could do something like four for this one.
And then basically we're just going to continue copying this.
And then we could do it for our median value.
We'll put a key in here that represents for example our coin pile is a median value.
And we'll make a reference to our coin pile.
The max allowed on the map.
We could do something like eight, and then the next, uh, medium value item is our money pile.
We'll make a reference to that as well.
Money pile.
We can also have a max of eight of those on the map.
And then the last medium value item is our silver bar pile.
So we could call it silver pile.
And again, we'll make a reference to our silver pile, and the max of those will allow on the map we
could do something like five.
Then we can copy all of these again and fill out the low value section.
So one of the low value section items is just going to be money, which will just represent a dollar
bill.
So it's called money the max allowed on the map.
We could do something like 15.
We'll have I believe a coin is our next low value item.
So we'll refer to our coin.
The max will allow on the map we could do 15.
And then the last low value item is going to be our silver bar.
And we'll make a reference to that as well.
Silver bar and the Max will allow on the map would be ten.
Last but not least, we need to make a reference to all of the different money item positions inside
of server storage.
So we could call this variable money item positions equal to server storage, dot money items, dot
money item positions.
And we want to get all of the children that are inside of that folder.
And we're also going to need a random data type.
Now we're going to need a few private functions.
One of the first private functions we're going to need is for when one of our money items gets clicked.
So inside each of our money items we have a click part that has a click detector.
And we want to listen for when that click detector gets clicked.
So every time we're spawning these different money items on the map, we want to connect a function
to each of the click detectors.
So we can call this function on money item clicked.
And that will handle, you know, giving players money and things like that.
We're going to need a function.
To set up or basically place all the money items on the map so we can call this function place money
items randomly on map.
And since this function is going to have to loop through many different positions that have different
values, I think it would be best if we create another dedicated function for spawning a money item
or a random money item based on a past value.
So we can have a function called spawn money item, and this function can get past a value which will
be low, medium, high or any.
And we will also get the part or basically the position where we need to place this money item at.
And let me make sure to denote this as a function as well.
Now before this function can actually go ahead and spawn whatever money item on the map, we actually
need to verify that a we have enough stock for this, whatever value that we're trying to spawn a money
item.
And we also got to make sure that we haven't exceeded the max allowed, uh, level or number based on
the money item that we're trying to spawn.
So that means we'll need another function.
And we can call this function something like get available items to spawn of a particular value.
And we'll pass a value to this as well.
So basically when this function gets called it's going to loop through all the positions and spawn a
money item based on a particular value.
And this function is going to verify or basically get all of the items that we can actually spawn on
this value.
So it's going to make sure that, you know we aren't out of stock and that, you know, are currently
on map number, doesn't exceed our max allowed and things like that.
And then when all of that checks out, then it can actually spawn the money items on our map.
Another function we're going to need is to listen to our game comms event.
So we can just call this on game comms event.
We could pass an action and arguments.
And if you remember, the only action we need to listen to for right now is in our game Comms enum server.
And that's going to be money service, not place money items.
And I don't know why I named that enum.
This should be named event.
So basically, when we get told to place money items on the map, we're going to call our place money
items randomly on map function.
And what this function is going to do is it's going to loop through every single different money item
positions on the map.
But we want to do it randomly.
So what we could do is we could have a for loop that starts at an index of one, and we could get the
total number of items within our money item positions table.
And then inside of this loop, what we're going to do is we're going to generate a random integer.
Between, uh, one and the number of elements in our, uh, money items positions table.
Because after we've spawned this item, uh, based on this random position we've grabbed based on this
random number, we're going to remove it from our money item positions table and pass random int at
the end here.
So that way we're not spawning multiple items at the same position.
But basically what we're going to do is we're going to get the part that is stored in this table by
indexing money item positions with this random integer.
So we're going to go ahead and get this position or this part.
And then we can call our spawn money item function.
And we'll pass uh the attribute for this part.
So part get attribute spawn value.
And then we're also going to pass the part itself.
And we should be good to go there.
So then inside of our spawn money item function, what we need to do is we need to get all of the possible
different money items that we can spawn based on this value.
So we create a table called something like Possible objects to spawn.
And this would get returned to us from our get available Items of value function.
And we would pass the value here.
And now let's hop into this function and fill this out.
So what we want to do in here is we want to create a table.
We'll call it possible objects to spawn.
And then what we're going to check is we're going to check the value passed to this function.
If the value is equal to any meaning that we can spawn any type of money item at a particular position,
then what we need to do is we need to loop through our money items table and go through each one of
our different money items, and ensure that we can spawn it by comparing the max allowed to the currently
on map number.
So if the value is equal to any, we need to loop through every single list of items in our money items
table.
And what we need to do with each one of these lists of money items is we need to loop through it as
well.
So for every single money item in our items table, what we need to do is we need to check if this money
item dot currently on map is greater than or equal to the money item dot max allowed number.
If it is, then we're just going to continue looping because we have reached the maximum amount of this
particular money item that could be spawned on the map.
If we haven't, then we can go ahead and insert this money item into our possible objects to spawn table,
and we're going to pass the money item dot model.
Now, if the value passed to this function isn't any and it's a particular value such as low, medium
or high, then what we need to do is we could just basically copy this loop here, and we want to loop
through every single money item inside of our money items table.
And we want to pass the value here.
So we're looping through every single money item.
And we're making sure that we can spawn that money item.
And if we can, we're inserting it into our possible objects to spawn table.
And then once we do that, we can just go ahead and return possible objects to spawn at the end.
So this function will grab for us all of the possible money items that we can spawn based on the value
or the string that was passed to our function.
Anyways, back into our spawn money item function.
Once we actually get all the possible objects we can spawn on the map, the next thing that we need
to do is we actually need to check if the number of possible objects to spawn is greater than zero,
if it is equal to zero, or basically there's nothing in the table, then we need to return out of this
function, because apparently the value that we pass to spawn has already been filled up, and we cannot
spawn any more of those objects, so we need to return.
But if we do have possible objects to spawn, then what we could do is we could create a clone of this
object by going in our possible objects to spawn table.
And then using RNG.
Next integer will pass one to the number of possible objects to spawn.
That way we're spawning a random object and we're going to clone this object.
And then what we're going to do is we're going to go into money items.
And then we're going to get our clone and get the attribute spawn value.
We'll pass the clone dot name.
And then we're going to set the currently on map key value pair plus equal one because we're adding
a new one on the map.
And now here is where we can spawn our clone onto the map.
Thankfully all of our money items are models.
So we can just basically first make sure that our clone is a model.
So if our clone is a model.
And what we need to do is we need to set the keyframe on this model by using the pivot two function.
And inside of here we're going to have to pass a lot, but basically we're going to create a new key
frame.
And the key frame is going to be equal to uh, what we're going to get is we're going to get the part
dot position or basically the part that we need to spawn this clone at.
We get the position of that part, and then we subtract that position by a vector three.
And this vector three is going to be zero on the x axis.
But on the y axis we're going to pass the part dot size dot y and divide that by two.
And then we're going to pass zero for the z axis.
Then we need to add a another offset using vector three dot new.
And this is going to be zero on the x axis.
But we're going to do is we're going to get our clone.
And since it's a model to get the full size of it we use a function called get extents size.
And this returns the size of the smallest bounding box that contains all of the base parts within the
model.
So basically we're just getting the full size of our model.
And then um, we can get the Y position out of this.
And then we want to divide this by two.
So basically we're just getting half the height of our model.
And we're adding this to our key frame.
We'll actually let me draw this out because it would be easier to understand this way.
Let's say we have a part here.
And this is the position where we need to spawn our money item.
And then we have our money item here.
And it's like this size and it has this origin point two first we subtract and we get the position right
here.
Right.
Because we subtracted by half of this positions uh height in its y axis.
Then what we're doing is we're adding the height of our origin point and our other part.
So we're getting half the height of the total size of our model.
Right, which would be this amount.
And we're adding this.
We're basically moving this position to the equivalent position that would be in the center of our object.
And then from that point we can literally just position our object at this new position that we set.
And that means our part would be, you know, completely flush at the correct position wherever this
position was sitting.
And then for the Z position, we can go ahead and make that zero because we're only concerned about
the Y position.
And then once we do that, we could basically just add a C frame angles and randomly rotate this part
around its y axis.
So we'll pass zero for the x axis.
And then we can do math dot rad and do orange.
Next integer.
Pass a number anywhere between -360 and 360.
Because I don't really care how we rotate it.
And then zero for the z axis.
And that's basically all we need to do.
So we're getting a new C frame of a position that's flush with the surface that we want to set our part
on, and then we're adding an offset based on the height on the y axis for our money item divided by
two.
So we get the center and then we just rotate it randomly.
So our model should be perfectly flush with whatever surface we need to position it to.
After that, we can set the clone dot parent equal to the workspace.
And inside the workspace inside of Krusty Krab, there's a folder called Money Items.
And then when our clone dot click part gets clicked, so there's a click detector in there.
We listen for when that gets clicked.
And we're going to connect a lambda function.
We'll get the player that clicked.
And then we can call our money item clicked function.
We can pass the player who clicked.
And then we can also pass the money item itself to this function.
Now we can go ahead and fill out our on money item clicked function.
So up here we get passed a player.
And then we also get past the money object.
And what we're going to do is we're going to check whether or not this player cheated.
So if this is an exploiter trying to collect all the money around the map at once when they're not even
close to one, then we need to kick them so we can check whether or not they cheated and get a message
from our anti-cheat using the check player distanced object.
We're going to pass our player.
We're going to, uh, pass our money object dot click part because that's what the distance we want
to check the player and then the distance or the max distance they're allowed to be away from.
This click part is going to be money object dot click part dot click detector dot max activation distance.
So if somehow the player exceeds that threshold we can check if they cheated.
If they did then we're going to kick this player, give them the message and then just return out of
this function.
Otherwise if they didn't cheat then we can destroy this money object and then we can access this player's
leaderstats folder, get their money int value, and set the value plus equal to the money object.
And actually we should destroy this afterwards.
So that way we can actually get the attribute of the money object.
So money object get attribute.
Money value, so we're giving the player the money they deserve.
And then we can use the update GUI event and fire to this particular player that they successfully collected
money.
So we can do the GUI actions enum of collected money and the amount that they collected.
The number is going to be equal to the money object, get attribute money value.
And again we can actually just create a variable for this.
So we can just call this money value equal to money object get attribute money value.
And then we can destroy the object.
And since we've already stored the value in here, we can just pass that here.
And then we can also pass that here as well.
And actually, one more thing we need to fill out here is we need to put in an initialize function.
So money service init.
What this will do is it'll listen to our game and comms event dot event and connect our on Gamescom
event function.
And in order to test our money service out, since we don't have any scripts currently that fire this
event and pass the action of place money items temporarily, what we could do is we could create a start
function that will just call our place money items randomly on map.
So this is just temporary.
I plan to remove this once we actually have a different script to fire this event, to tell the service
to start placing the money items on the map.
But now we should be able to test this out.
So let's go ahead and see.
Let's just make sure that we didn't have any errors.
So we loaded the money service.
And then did we start?
Failed to start money service.
Actually we did get an error here.
Let's go ahead and see what the problem is.
So on line 119 invalid argument number one see frame expected got vector three.
So let's go ahead and see what the problem is on line 119.
So if we go to our money service line 119 apparently we're getting an error here.
So let's see.
So we're trying to pivot this to a new key frame.
So we get our key frame dot new here based on this position.
And I believe what we actually need to do is we should copy this here.
And we're going to place that inside of our C frame.
So.
To that.
We'll do it right here.
And then we multiply it by the keyframed angles.
So I believe we just had a little bit of an error with our parentheses.
But now we should actually be passing a keyframe with a random rotation.
So let's go ahead and try that out again.
So we'll test it out here and we'll go to view it on the server.
And perfect.
There we go.
As you can see our money items have randomly generated on the map.
And you can also see that each of our money items, despite their weird size here they are flush with
the surface that our position was set to.
And that's because we did a little bit of that math calculation to make sure that our objects are flush
with the surface that they need to go onto.
So as you can see, everything looks good.
We have our money items randomly placed all around the map.
There's one down there.
We should have some other ones in here.
There's one right there.
There should be one in the restroom as well.
There's one.
And we should have our other money items.
If I move my mouse around, there should be one.
Yep, there's one right there and there should be one right here.
Perfect.
So all of our money items look like they have successfully generated on our map.
So we're back on the client.
We're going to have to wait for our client to show back up at the restaurant.
Alrighty, now we should be able to protest whether or not we get that money collection guy thing on
our screen.
So let's go ahead and find a money item like this one over here.
If we click it perfect, we get plus $2.
And as you can see, the guy popped up on our screen.
Got $5.
And as you can see, it's also adding it to the leaderboard.
So I add this one gives me my money plus five.
We collect this one plus 15.
Collect this one down here plus 25.
Very nice.
And actually another thing I could test real quick is to see whether or not we get that little message
on the bottom of our screen.
Because this door is locked, it should tell us that the door is locked.
So if we interact.
Huh?
It's not displaying the message, but we are getting the sound played on our end.
So there might be an issue with the little, uh, text at the bottom of our screen.
So let's actually verify this real quick.
So inside of our main guy handler, we should go to our display small message function.
Here we go.
Let's see if there's any issues.
Um, well, we should be fading the element to be opaque, so it should be visible on our screen.
Let's go ahead and look inside of our main GUI and look at our small message label.
Oh, and that's the problem.
The visibility for our small message label is disabled.
So what we can do in here is we can make sure it's enabled by referencing our small message label and
make sure the visibility is set to true.
That should fix our problem now.
So let me go ahead and verify everything else.
Looks good.
All right.
Everything else looks good.
Let's go ahead and try that out again.
All right.
If we go interact with the door there we go.
We get our little message.
The door is locked.
If we try to do it again, it fades it out and pops that one back in.
If we keep spamming it, you can see it keeps overriding the previous messages.
Perfect.
So it looks like our small message system is working great as well.
Otherwise that's all I have for you in this lecture.
I'll see you in the next one.